from django.shortcuts import render
from django.views import View
from django.http import HttpResponse,JsonResponse
from django_redis import get_redis_connection

from verifications.libs.captcha.captcha import captcha
from verifications.libs.yuntongxun.ccp_sms import CCP
from celery_tasks.sms.tasks import ccp_send_sms_code

import re,random
# Create your views here.

# 获取图形验证码
class ImageCodeView(View):

    def get(self, request, uuid):
        # 1、提取参数
        # 2、校验参数

        # 3、业务数据处理
        # 3.1、调用captcha外部库生成图片和验证码
        text, img_bytes = captcha.generate_captcha()
        print("验证码：", text)

        # 3.2、把验证码写入redis(以uuid作为key)
        # get_redis_connection函数：功能是获取redis链接对象，参数是一个字符串(是django缓存配置名称)
        # 返回值是一个redis链接对象
        conn = get_redis_connection('verify_code') # 2号库
        # setex img_37728d6c-e219-44c5-8f81-4245a9e557a4 300 KJHG
        conn.setex('img_%s'%uuid, 300, text)

        # 4、构建响应(返回图片数据)
        # 构造的响应体数据是图片的二进制字节数据，需要设置响应头Content-Type:image/jpeg，来
        # 告诉浏览器响应体数据是图片数据，这样浏览器才能够渲染图片
        return HttpResponse(img_bytes, content_type='image/jpeg')


# 获取短信验证码
class SMSCodeView(View):

    def get(self, request, mobile):
        # 1、提取参数
        image_code = request.GET.get('image_code') # 用户手动填写的图形验证码
        image_code_id = request.GET.get('image_code_id') # 图形验证码对应的uuid

        # 2、校验参数
        # 2.1、必要性校验
        if not all([image_code, image_code_id]):
            return JsonResponse({'code': 400, 'errmsg': '缺少必要参数'})
        # 2.2、格式校验
        if not re.match(r'^[a-zA-Z0-9]{4}$', image_code):
            return JsonResponse({'code': 400, 'errmsg': '图形验证码有误'})
        if not re.match(r'^[0-9a-f]{8}(-[0-9a-f]{4}){3}-[0-9a-f]{12}$', image_code_id):
            return JsonResponse({'code': 400, 'errmsg': 'uuid有误'})

        # 2.3、业务性校验
        # TODO: 校验用户填写的图形验证码和redis中存储的图形验证码是否一致
        conn = get_redis_connection('verify_code') # 2号库
        # conn.get()函数返回值是一个字节如：b'AHGF'   或者  None(图形验证码过期)
        redis_image_code = conn.get('img_%s'%image_code_id)
        # TODO: 为了避免图形验证码被重复使用，我们需要遵循一个原则："读一次删一次"
        conn.delete('img_%s'%image_code_id)
        if not redis_image_code:
            # redis图形验证码过期
            return JsonResponse({'code': 400, 'errmsg': '图形验证码过期'})

        # 'AHGF'  !=  b'AHGF'.decode() --> 'AHGF'  !=  'AHGF'
        # 统一转化小写比对 —— 忽略大小写
        if image_code.lower() != redis_image_code.decode().lower():
            return JsonResponse({'code': 400, 'errmsg': '图形验有误'}, status=400)

        # 3、业务数据处理
        # TODO: 发短信验证码
        # **发送短信之前，需要判断标志存不存在**
        flag = conn.get('flag_%s'%mobile)
        if flag:
            # 如果flag存在，则表明60秒之内发送过短信，此时不允许再发送
            return JsonResponse({'code': 400, 'errmsg': '请勿重复发送，60秒后再尝试'})

        sms_code = "%06d" % random.randrange(0, 999999)
        print("短信验证码: ", sms_code)
        # 3.1、存储短信验证码到redis中(便于在注册接口中比对校验)
        p = conn.pipeline() # 获取管道对象
        # setex sms_18588269037 300 123456
        p.setex('sms_%s'%mobile, 300, sms_code)
        # **发送短信成功，记录标志信息为期60秒，表示60秒中之内发送过短信**
        p.setex('flag_%s' % mobile, 60, -1)
        p.execute() # 通过管道对象的execute函数调用把之前搜集的指令一次性发送给redis批量执行

        # 3.2、使用yuntongxun发送短信(携带短信验证码)
        # ======普通同步发送短信======
        # ccp = CCP()
        # ccp.send_template_sms(
        #     mobile,
        #     [sms_code, 5], # 5分钟提示有效期一定要和redis存储短信验证码有效期保持一致
        #     1 # 由于测试账号云通讯只提供了id为1的短信模版
        # )
        # TODO：======异步发送短信======
        # 以异步方式调用
        ccp_send_sms_code.delay(mobile, sms_code)

        # 4、构建响应
        return JsonResponse({'code': 0, 'errmsg': 'ok'})










